local Class = require('lua.lang.Class')
local Lua = require('lua.vm.Lua')
local LuaError = require('lua.vm.LuaError')

--- @class Constants : Lua
local Constants = Class {
	__extends = Lua
}

Constants.MAXSTACK = 250
Constants.LUAI_MAXUPVAL = 0xff
Constants.LUAI_MAXVARS = 200
Constants.NO_REG = Constants.MAXARG_A

Constants.iABC = 0
Constants.iABx = 1
Constants.iAsBx = 2

Constants.OpArgN = 0
Constants.OpArgU = 1
Constants.OpArgR = 2
Constants.OpArgK = 3

Constants.EOZ = -1
Constants.MAX_INT = 2147483645
Constants.UCHAR_MAX = 255
Constants.LUAI_MAXCCALLS = 200
Constants.LUA_COMPAT_LSTR = 1
Constants.LUA_COMPAT_VARARG = true
Constants.NO_JUMP = -1
Constants.OPR_ADD = 0
Constants.OPR_SUB = 1
Constants.OPR_MUL = 2
Constants.OPR_DIV = 3
Constants.OPR_MOD = 4
Constants.OPR_POW = 5
Constants.OPR_IDIV = 15
Constants.OPR_BAND = 16
Constants.OPR_BOR = 17
Constants.OPR_BXOR = 18
Constants.OPR_SHL = 19
Constants.OPR_SHR = 20
Constants.OPR_CONCAT = 6
Constants.OPR_NE = 7
Constants.OPR_EQ = 8
Constants.OPR_LT = 9
Constants.OPR_LE = 10
Constants.OPR_GT = 11
Constants.OPR_GE = 12
Constants.OPR_AND = 13
Constants.OPR_OR = 14
Constants.OPR_NOBINOPR = 21
Constants.OPR_MINUS = 0
Constants.OPR_NOT = 1
Constants.OPR_LEN = 2
Constants.OPR_BNOT = 3
Constants.OPR_NOUNOPR = 4
Constants.VVOID = 0
Constants.VNIL = 1
Constants.VTRUE = 2
Constants.VFALSE = 3
Constants.VK = 4
Constants.VKNUM = 5
Constants.VNONRELOC = 6
Constants.VLOCAL = 7
Constants.VUPVAL = 8
Constants.VINDEXED = 9
Constants.VJMP = 10
Constants.VRELOCABLE = 11
Constants.VCALL = 12
Constants.VVARARG = 13

--- @param b boolean
--- @return void
function Constants:assert(b)
	if not b then
		LuaError:new('compiler assert failed'):throw()
	end
end

--- @param i InstructionPointer
--- @param o number
--- @return void
function Constants:setOpCode(i, o)
	i:set((i:get() & (self.MASK_NOT_OP)) | ((o << self.POS_OP) & self.MASK_OP))
end

--- @param i InstructionPointer
--- @param u number
--- @return void
function Constants:setArgA(i, u)
	i:set((i:get() & (self.MASK_NOT_A)) | ((u << self.POS_A) & self.MASK_A))
end

--- @param i InstructionPointer
--- @param u number
--- @return void
function Constants:setArgB(i, u)
	i:set((i:get() & (self.MASK_NOT_B)) | ((u << self.POS_B) & self.MASK_B))
end

--- @param i InstructionPointer
--- @param u number
--- @return void
function Constants:setArgC(i, u)
	i:set((i:get() & (self.MASK_NOT_C)) | ((u << self.POS_C) & self.MASK_C))
end

--- @param i InstructionPointer
--- @param u number
--- @return void
function Constants:setArgBx(i, u)
	i:set((i:get() & (self.MASK_NOT_Bx)) | ((u << self.POS_Bx) & self.MASK_Bx))
end

--- @param i InstructionPointer
--- @param u number
--- @return void
function Constants:setArgSbx(i, u)
	self:setArgBx(i, u + self.MAXARG_sBx)
end

--- @param o number
--- @param a number
--- @param b number
--- @param c number
--- @return number
function Constants:createABC(o, a, b, c)
	return ((o << self.POS_OP) & self.MASK_OP) |
			((a << self.POS_A) & self.MASK_A) |
			((b << self.POS_B) & self.MASK_B) |
			((c << self.POS_C) & self.MASK_C)
end

--- @param o number
--- @param a number
--- @param bc number
--- @return number
function Constants:createAbx(o, a, bc)
	return ((o << self.POS_OP) & self.MASK_OP) |
			((a << self.POS_A) & self.MASK_A) |
			((bc << self.POS_Bx) & self.MASK_Bx)
end

--- @param o number
--- @param a number
--- @return number
function Constants:createAx(o, a)
	return (o & 63) | ((a << 6) & -64)
end

return Constants